home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / main.c < prev    next >
C/C++ Source or Header  |  1994-02-11  |  41KB  |  1,548 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "version.h"
  9. #include "cookie.h"
  10. #include "xbra.h"
  11.  
  12. /* the kernel's stack size */
  13. #define STACK    8*1024L
  14.  
  15. /* if the user is holding down the magic shift key, we ask before booting */
  16. #define MAGIC_SHIFT 0x2        /* left shift */
  17.  
  18. /* magic number to show that we have captured the reset vector */
  19. #define RES_MAGIC 0x31415926L
  20.  
  21. static void xbra_install P_((xbra_vec *, long, long ARGS_ON_STACK (*)()));
  22. static void init_intr P_((void));
  23. static long getmch P_((void));
  24. static void do_line P_((char *));
  25. static void do_file P_((int));
  26. static void shutmedown P_((PROC *));
  27. void shutdown P_((void));
  28. static void doset P_((char *,char *));
  29. static long ARGS_ON_STACK mint_criticerr P_((long));
  30. static void ARGS_ON_STACK do_exec_os P_((register long basepage));
  31.  
  32. static int gem_active;    /* 0 if AES has not started, nonzero otherwise */
  33.  
  34. #define EXEC_OS 0x4feL
  35. static int  check_for_gem P_((void));
  36. static void run_auto_prgs P_((void));
  37.  
  38. #ifdef LATTICE
  39. /*
  40.  * AGK: this is witchcraft to completely replace the startup code for
  41.  * Lattice; doing so saves around 10K on the final binary and pulls only
  42.  * long division & multitplication from the library (and not even those
  43.  * if you compile for native '030). The drawback of this code is it
  44.  * passes no environment or command line whatsoever. Since I always
  45.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  46.  * downer, however at some point in the future we ought to have a kernel
  47.  * parseargs() like call which sets these things up.
  48.  */ 
  49. BASEPAGE *_base;
  50.  
  51. static void
  52. start(BASEPAGE *bp)
  53. {
  54.     long shrinklen;
  55.     
  56.     _base = bp;
  57.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  58.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  59.         static char null[1] = {""};
  60.         static char *argv[2] = {null, NULL};
  61.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  62.  
  63.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  64.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  65.         main(1, argv);
  66.     }
  67.     Pterm(ENSMEM);
  68. }
  69. #endif
  70.  
  71. #if defined(__GNUC__) || defined(__MINT__)
  72. long _stksize = STACK;
  73. #ifndef PROFILING
  74. #include <minimal.h>
  75. #endif
  76. #endif
  77.  
  78. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  79. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  80.  
  81. /*
  82.  * AGK: for proper co-processors we must consider saving their context.
  83.  * This variable when non-zero indicates that the BIOS considers a true
  84.  * coprocessor to be present. We use this variable in the context switch
  85.  * code to decide whether to attempt an FPU context save.
  86.  */
  87. short fpu = 0;
  88.  
  89. /*
  90.  * "mch" holds what kind of machine we are running on
  91.  */
  92. long mch = 0;
  93.  
  94. /*
  95.  * "screen_boundary+1" tells us how screens must be positioned
  96.  * (to a 256 byte boundary on STs, a 16 byte boundary on other
  97.  * machines; actually, 16 bytes is conservative, 4 is probably
  98.  * OK, but it doesn't hurt to be cautious). The +1 is because
  99.  * we're using this as a mask in the ROUND() macro in mem.h.
  100.  */
  101. int screen_boundary = 255;
  102.  
  103. /*
  104.  * variable holds processor type
  105.  */
  106. long mcpu = 0;
  107.  
  108. /*
  109.  * variable holds language preference
  110.  */
  111. int gl_lang = -1;
  112.  
  113. /*
  114.  * variable set if someone has already installed an flk cookie
  115.  */
  116. int flk = 0;
  117.  
  118. /*
  119.  * variable set to 1 if the _VDO cookie indicates Falcon style video
  120.  */
  121. int FalconVideo;
  122.  
  123. /* program to run at startup */
  124. #ifdef MULTITOS
  125. static int init_is_gem = 1;    /* set to 1 if init_prg is GEM */
  126. #else
  127. static int init_is_gem = 0;    /* set to 1 if init_prg is GEM */
  128. #endif
  129. static const char *init_prg = 0;
  130.  
  131. /* note: init_tail is also used as a temporary stack for resets in
  132.  * intr.spp
  133.  */
  134. char init_tail[256];
  135.  
  136. /* initial environment for that program */
  137. static char *init_env = 0;
  138. /* temporary pointer into that environment for setenv */
  139. static char *env_ptr;
  140. /* length of the environment */
  141. static long env_len;
  142.  
  143. /* GEMDOS pointer to current basepage */
  144. BASEPAGE **tosbp;
  145.  
  146. /* pointer to the BIOS keyboard shift variable */
  147. extern char *kbshft;    /* see bios.c */
  148.  
  149. /* version of TOS we're running over */
  150. int tosvers;
  151.  
  152. /* structures for keyboard/MIDI interrupt vectors */
  153. KBDVEC *syskey, oldkey;
  154. xbra_vec old_ikbd;            /* old ikbd vector */
  155.  
  156. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  157. long save_dos, save_bios, save_xbios;
  158.  
  159. /* values for original system vectors */
  160. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  161. xbra_vec old_criticerr;
  162. xbra_vec old_execos;
  163.  
  164. long old_term;
  165.  
  166. xbra_vec old_resvec;    /* old reset vector */
  167. long old_resval;    /* old reset validation */
  168.  
  169. #ifdef EXCEPTION_SIGS
  170. /* bus error, address error, illegal instruction, etc. vectors */
  171. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  172. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  173. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  174. #endif
  175.  
  176. /* BIOS disk vectors */
  177. xbra_vec old_mediach, old_getbpb, old_rwabs;
  178.  
  179. /* BIOS drive map */
  180. long olddrvs;
  181.  
  182. extern Func bios_tab[], dos_tab[];
  183.  
  184. /* kernel info that is passed to loaded file systems and device drivers */
  185.  
  186. struct kerinfo kernelinfo = {
  187.     MAJ_VERSION, MIN_VERSION,
  188.     DEFAULT_MODE, 0,
  189.     bios_tab, dos_tab,
  190.     changedrv,
  191.     Trace, Debug, ALERT, FATAL,
  192.     kmalloc, kfree, umalloc, ufree,
  193.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  194.     ms_time, unixtim, dostim,
  195.     nap, sleep, wake, wakeselect,
  196.     denyshare, denylock, addtimeout, canceltimeout
  197. };
  198.  
  199. /* table of processor frame sizes in _words_ (not used on MC68000) */
  200. unsigned char framesizes[16] = {
  201. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  202. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  203. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  204. /*3*/    2,    /* M68040 floating point post instruction */
  205. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  206. /*5*/    0,    /* NOTUSED */
  207. /*6*/    0,    /* NOTUSED */
  208. /*7*/    26,    /* M68040 access error */    
  209. /*8*/    25,    /* MC68010 long */    
  210. /*9*/    6,    /* M68020/M68030 mid instruction */
  211. /*A*/    12,    /* M68020/M68030 short bus cycle */
  212. /*B*/    42,    /* M68020/M68030 long bus cycle */
  213. /*C*/    8,    /* CPU32 bus error */
  214. /*D*/    0,    /* NOTUSED */
  215. /*E*/    0,    /* NOTUSED */
  216. /*F*/    13    /* 68070 and 9xC1xx microcontroller address error */
  217. };
  218.  
  219. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  220.  * after main() for further details
  221.  */
  222.  
  223. COOKIE *oldcookie, *newcookie;
  224.  
  225. /*
  226.  * install a new vector for address "addr", using the XBRA protocol.
  227.  * must run in supervisor mode!
  228.  */
  229.  
  230. static void
  231. xbra_install(xv, addr, func)
  232.     xbra_vec *xv;
  233.     long addr;
  234.     long ARGS_ON_STACK (*func)();
  235. {
  236.     xv->xbra_magic = XBRA_MAGIC;
  237.     xv->xbra_id = MINT_MAGIC;
  238.     xv->jump = JMP_OPCODE;
  239.     xv->this = func;
  240.     xv->next = *((struct xbra **)addr);
  241.     *((short **)addr) = &xv->jump;
  242. }
  243.  
  244. /*
  245.  * MiNT critical error handler; all it does is to jump through
  246.  * the vector for the current process
  247.  */
  248.  
  249. static long ARGS_ON_STACK
  250. mint_criticerr(error)
  251.     long error;    /* high word is error, low is drive */
  252. {
  253.     return (*curproc->criticerr)(error);
  254. }
  255.  
  256. /*
  257.  * if we are MultiTOS, and if we are running from the AUTO folder,
  258.  * then we grab the exec_os vector and use that to start GEM; that
  259.  * way programs that expect exec_os to act a certain way will still
  260.  * work.
  261.  * NOTE: we must use Pexec instead of p_exec here, because we will
  262.  * be running in a user context (that of process 1, not process 0)
  263.  */
  264.  
  265. static void ARGS_ON_STACK
  266. do_exec_os(basepage)
  267.     register long basepage;
  268. {
  269.     register long r;
  270.  
  271. /* if the user didn't specify a startup program, jump to the ROM */
  272.     if (!init_prg) {
  273.         register void ARGS_ON_STACK (*f) P_((long));
  274.         f = (void ARGS_ON_STACK (*) P_((long))) old_execos.next;
  275.         (*f)(basepage);
  276.         Pterm0();
  277.     } else {        
  278.  
  279. /* we have to set a7 to point to lower in our TPA; otherwise we would
  280.  * bus error right after the Mshrink call!
  281.  */
  282.         setstack(basepage+500L);
  283. #if defined(__TURBOC__) && !defined(__MINT__)
  284.         Mshrink(0, (void *)basepage, 512L);
  285. #else
  286.         Mshrink((void *)basepage, 512L);
  287. #endif
  288.         r = Pexec(200, (char *)init_prg, init_tail, init_env);
  289.         Pterm((int)r);
  290.     }
  291. }
  292.  
  293.  
  294. /* initialize all interrupt vectors and new trap routines
  295.  * we also get here any TOS variables that we're going to change
  296.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  297.  * restore them.
  298.  */
  299.  
  300. static void
  301. init_intr()
  302. {
  303.     extern long ARGS_ON_STACK mint_bios();
  304.     extern long ARGS_ON_STACK mint_dos();
  305.     extern long ARGS_ON_STACK mint_timer();
  306.     extern long ARGS_ON_STACK mint_vbl();
  307.     extern long ARGS_ON_STACK mint_5ms();
  308.     extern long ARGS_ON_STACK mint_xbios();
  309.     extern long ARGS_ON_STACK reset();
  310.       extern long ARGS_ON_STACK new_ikbd();
  311.       extern long ARGS_ON_STACK new_bus();
  312.       extern long ARGS_ON_STACK new_addr();
  313.       extern long ARGS_ON_STACK new_ill();
  314.       extern long ARGS_ON_STACK new_divzero();
  315.       extern long ARGS_ON_STACK new_trace();
  316.       extern long ARGS_ON_STACK new_priv();
  317.       extern long ARGS_ON_STACK new_linef();
  318.       extern long ARGS_ON_STACK new_chk();
  319.       extern long ARGS_ON_STACK new_trapv();
  320.       extern long ARGS_ON_STACK new_fpcp();
  321.       extern long ARGS_ON_STACK new_mmu();
  322.       extern long ARGS_ON_STACK new_format();
  323.       extern long ARGS_ON_STACK new_cpv();
  324.       extern long ARGS_ON_STACK new_uninit();
  325.       extern long ARGS_ON_STACK new_spurious();
  326.       extern long ARGS_ON_STACK new_pmmuacc();
  327.     short savesr;
  328.     int i;
  329.  
  330.     syskey = (KBDVEC *)Kbdvbase();
  331.     oldkey = *syskey;
  332.  
  333.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  334.  
  335. /* gratuitous (void *) for Lattice */
  336.     old_term = (long)Setexc(0x102, (void *)-1UL);
  337.  
  338.     savesr = spl7();
  339.  
  340.     xbra_install(&old_dos, 0x84L, mint_dos);
  341.     save_dos = (long)old_dos.next;
  342.  
  343.     xbra_install(&old_bios, 0xb4L, mint_bios);
  344.     save_bios = (long)old_bios.next;
  345.  
  346.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  347.     save_xbios = (long)old_xbios.next;
  348.  
  349.     xbra_install(&old_timer, 0x400L, mint_timer);
  350.     xbra_install(&old_criticerr, 0x404L, mint_criticerr);
  351.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  352.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  353.     xbra_install(&old_resvec, 0x42aL, reset);
  354.     old_resval = *((long *)0x426L);
  355.     *((long *)0x426L) = RES_MAGIC;
  356.  
  357.     spl(savesr);
  358.  
  359. #ifdef EXCEPTION_SIGS
  360. /* set up signal handlers */
  361.     xbra_install(&old_bus, 8L, new_bus);
  362.     xbra_install(&old_addr, 12L, new_addr);
  363.     xbra_install(&old_ill, 16L, new_ill);
  364.     xbra_install(&old_divzero, 20L, new_divzero);
  365.     xbra_install(&old_trace, 36L, new_trace);
  366.     xbra_install(&old_priv, 32L, new_priv);
  367.     if (tosvers >= 0x106)
  368.         xbra_install(&old_linef, 44L, new_linef);
  369.     xbra_install(&old_chk, 24L, new_chk);
  370.     xbra_install(&old_trapv, 28L, new_trapv);
  371.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  372.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  373.     }
  374.     xbra_install(&old_mmuconf, 224L, new_mmu);
  375.     xbra_install(&old_pmmuill, 228L, new_mmu);
  376.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  377.     xbra_install(&old_format, 56L, new_format);
  378.     xbra_install(&old_cpv, 52L, new_cpv);
  379.     xbra_install(&old_uninit, 60L, new_uninit);
  380.     xbra_install(&old_spurious, 96L, new_spurious);
  381. #endif
  382.  
  383. /* set up disk vectors */
  384.     xbra_install(&old_mediach, 0x47eL, new_mediach);
  385.     xbra_install(&old_rwabs, 0x476L, new_rwabs);
  386.     xbra_install(&old_getbpb, 0x472L, new_getbpb);
  387.     olddrvs = *((long *)0x4c2L);
  388.  
  389. /* set up cookie jar */
  390.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  391.     install_cookies();
  392. }
  393.  
  394. /* restore all interrupt vectors and trap routines */
  395. /*
  396.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  397.  * Normally, one should trace through the XBRA chain. However, this is
  398.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  399.  * under MiNT will no longer exist, and so any vectors that they have
  400.  * caught will be pointing to never-never land! So we do something that
  401.  * would normally be considered rude, and restore the vectors to
  402.  * what they were before we ran.
  403.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  404.  */
  405.  
  406. void
  407. restr_intr()
  408. {
  409.     short savesr;
  410.     int i;
  411.  
  412.     savesr = spl7();
  413.     *syskey = oldkey;        /* restore keyboard vectors */
  414.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  415.     *CJAR = oldcookie;        /* restore old cookie jar */
  416.  
  417. #ifdef EXCEPTION_SIGS
  418.     *((long *)0x08L) = (long) old_bus.next;
  419.     *((long *)0x0cL) = (long) old_addr.next;
  420.     *((long *)0x10L) = (long) old_ill.next;
  421.     *((long *)0x14L) = (long) old_divzero.next;
  422.     *((long *)0x20L) = (long) old_priv.next;
  423.     *((long *)0x24L) = (long) old_trace.next;
  424.     if (old_linef.next)
  425.         *((long *)0x2cL) = (long) old_linef.next;
  426.     *((long *)0x18L) = (long) old_chk.next;
  427.     *((long *)0x1cL) = (long) old_trapv.next;
  428.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  429.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  430.     }
  431.     *((long *)0xe0L) = (long) old_mmuconf.next;
  432.     *((long *)0xe4L) = (long) old_pmmuill.next;
  433.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  434.     *((long *)0x38L) = (long) old_format.next;
  435.     *((long *)0x34L) = (long) old_cpv.next;
  436.     *((long *)0x3cL) = (long) old_uninit.next;
  437.     *((long *)0x60L) = (long) old_spurious.next;
  438. #endif
  439.     *((long *)0x84L) = (long) old_dos.next;
  440.     *((long *)0xb4L) = (long) old_bios.next;
  441.     *((long *)0xb8L) = (long) old_xbios.next;
  442.     *((long *)0x408L) = old_term;
  443.     *((long *)0x404L) = (long) old_criticerr.next;
  444.     *((long *)0x114L) = (long) old_5ms.next;
  445.     *((long *)0x400L) = (long) old_timer.next;
  446.     *((long *)0x70L) = (long) old_vbl.next;
  447.     *((long *)0x426L) = old_resval;
  448.     *((long *)0x42aL) = (long) old_resvec.next;
  449.     *((long *)0x476L) = (long) old_rwabs.next;
  450.     *((long *)0x47eL) = (long) old_mediach.next;
  451.     *((long *)0x472L) = (long) old_getbpb.next;
  452.     *((long *)0x4c2L) = olddrvs;
  453.  
  454.     spl(savesr);
  455. }
  456.  
  457.  
  458. /* we save the TOS supervisor stack pointer so that we can reset it when
  459.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  460.  */
  461.  
  462. long tosssp;        /* TOS supervisor stack pointer */
  463.  
  464.  
  465. /*
  466.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  467.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  468.  * sets up other vectors and system variables appropriately. Note that
  469.  * calling enter_kernel multiple times is probably NOT a good idea,
  470.  * but the code will allow it.
  471.  * The parameter is a flag telling us whether or not this is a GEMDOS
  472.  * call; the BIOS uses this for checking security of Rwabs.
  473.  */
  474.  
  475. short in_kernel = 0;
  476.  
  477. void ARGS_ON_STACK
  478. enter_kernel(isGEMDOS)
  479.     int isGEMDOS;
  480. {
  481.     short save_sr;
  482.  
  483.     if (in_kernel) return;
  484.  
  485.     save_sr = spl7();
  486.     curproc->in_dos = isGEMDOS;
  487.     save_dos = *((long *) 0x84L);
  488.     save_bios = *((long *) 0xb4L);
  489.     save_xbios = *((long *) 0xb8L);
  490.     *((long *) 0x84L) = (long)old_dos.next;
  491.     *((long *) 0xb4L) = (long)old_bios.next;
  492.     *((long *) 0xb8L) = (long)old_xbios.next;
  493.     *tosbp = _base;
  494.  
  495.     in_kernel = 1;
  496.     spl(save_sr);
  497. }
  498.  
  499. /*
  500.  * leave_kernel: called before leaving the kernel, either back to
  501.  * user mode or when calling a signal handler or the GEMDOS
  502.  * terminate vector. Note that interrupts should be disabled before
  503.  * this routine is called.
  504.  */
  505.  
  506. void ARGS_ON_STACK
  507. leave_kernel()
  508. {
  509.     *((long *) 0x84L) = save_dos;
  510.     *((long *) 0xb4L) = save_bios;
  511.     *((long *) 0xb8L) = save_xbios;
  512.     *tosbp = curproc->base;
  513.     in_kernel = 0;
  514.     curproc->in_dos = 0;
  515. }
  516.  
  517. /*
  518.  * shut down processes; this involves waking them all up, and sending
  519.  * them SIGTERM to give them a chance to clean up after themselves
  520.  */
  521.  
  522. static void
  523. shutmedown(p)
  524.     PROC *p;
  525. {
  526.     UNUSED(p);
  527.     curproc->wait_cond = 0;
  528. }
  529.  
  530. void
  531. shutdown()
  532. {
  533.     PROC *p;
  534.     int proc_left = 0;
  535.  
  536.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  537.  
  538.     for (p = proclist; p; p = p->gl_next) {
  539.         if (p->pid == 0) continue;
  540.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  541.             if (p->wait_q != READY_Q) {
  542.                 short sr = spl7();
  543.                 rm_q(p->wait_q, p);
  544.                 add_q(READY_Q, p);
  545.                 spl(sr);
  546.             }
  547.             post_sig(p, SIGTERM);
  548.             proc_left++;
  549.         }
  550.     }
  551.  
  552.     if (proc_left) {
  553.         /* sleep a little while, to give the other processes a chance to
  554.            shut down
  555.          */
  556.  
  557.         addtimeout(1000, shutmedown);
  558.         do {
  559.             sleep(WAIT_Q, (long)shutdown);
  560.         } while (curproc->wait_cond == (long)shutdown);
  561.     }
  562. }
  563.  
  564. #if defined(__GNUC__) || defined(__MINT__)
  565. int
  566. main(argc, argv, envp)
  567.     int argc;
  568.     char **argv, **envp;
  569. #else
  570. int
  571. main(argc, argv)
  572.     int argc;
  573.     char **argv;
  574. #endif
  575. {
  576.     long *sysbase;
  577.     long r;
  578.     extern int debug_level, debug_logging;    /* in debug.c */
  579.     extern int no_mem_prot;        /* memprot.c */
  580.     extern const char *greet1, *greet2;
  581.                     /* welcome.c */
  582.     static char buf[SPRINTF_MAX];
  583.     static char curpath[128];
  584.     long yn;
  585.     FILEPTR *f;
  586.  
  587. #if defined(__GNUC__) || defined(__MINT__)
  588.     UNUSED(envp);
  589. #endif
  590.  
  591. /* figure out what kind of machine we're running on */
  592. /* biosfs wants to know this; also sets no_mem_prot */
  593. /* 920625 kbad put it here so memprot_warning can be intelligent */
  594.     (void)Supexec(getmch);
  595. #ifdef ONLY030
  596.     if (mcpu != 30) {
  597.         Cconws("\r\nThis version of MiNT requires a 68030.\r\n");
  598.         Cconws("Hit any key to continue.\r\n");
  599.         (void)Cconin();
  600.         Pterm0();
  601.     }
  602. #endif
  603.  
  604. #ifdef MULTITOS
  605. /* Ask the user if s/he wants to boot MultiTOS or regular TOS */
  606.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  607.         yn = boot_kernel_p();
  608.         Cconws("\r\n");
  609.         if (!yn)
  610.             Pterm0();
  611.     }
  612. #else
  613. /* Allow the user to abort the boot if the magic combination of shift keys
  614.  * is held down (see MAGIC_SHIFT above)
  615.  */
  616.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  617.         Cconws("Boot MiNT? (y/n) ");
  618.         yn = Cconin() & 0x7f;
  619.         if (yn != 'y' && yn != 'Y') {
  620.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  621.             Pterm0();
  622.         }
  623.     }
  624. #endif
  625.  
  626.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  627.         curs_off = 1;
  628.     }
  629.  
  630.     yn = 0; /* by default, don't print basepage */
  631.     --argc, ++argv;
  632.     while (argc && **argv == '-') {
  633.         if (argv[0][1] >= '0' && argv[0][1] <= '9') {
  634.         /* a number sets out_device to that device */
  635.             extern int out_device;
  636.             out_device = (int)atol(&argv[0][1]);
  637.         }
  638.         else if (argv[0][1] == 'b') {
  639.         /* print MiNT basepage */
  640.             yn++;
  641.         }
  642.         else if (argv[0][1] == 'd') {
  643.         /* -d increases debugging level */
  644.             debug_level++;
  645.         }
  646.         else if (argv[0][1] == 'm' || argv[0][1] == 'p') {
  647.             int givenotice = (argv[0][2] != 'w');
  648.         /* -m and -p turn off memory protection */
  649.         extern const char *memprot_notice, *memprot_warning;
  650.             if (no_mem_prot) {
  651.                 if (givenotice)
  652.                 Cconws(memprot_notice);
  653.             }
  654.             else {
  655.                 no_mem_prot = 1;
  656.                 if (givenotice)
  657.                 Cconws(memprot_warning);
  658.             }
  659.         }
  660.         else if (argv[0][1] == 'l') {
  661.         /* -l turns on debug logging */
  662.             debug_logging = 1;
  663.         }
  664.         else {
  665.             Cconws("Unknown argument (ignored): ");
  666.             Cconws(*argv);
  667.             Cconws("\r\n");
  668.         }
  669.         ++argv, --argc;
  670.     }
  671.     if (argc) {
  672.         Cconws("Unknown argument ignored: ");
  673.         Cconws(*argv);
  674.         Cconws(" (and all the rest)\r\n");
  675.         }
  676.  
  677. /* greetings */
  678.     Cconws(greet1);
  679.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  680.     Cconws(buf);
  681.     Cconws(greet2);
  682.  
  683. #ifdef __TURBOC__
  684.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  685. #endif
  686.  
  687.     if (yn)
  688.     {
  689.             ksprintf(buf,"MiNT@%lx\r\nhit a key...",_base);
  690.         Cconws(buf);
  691.         (void)Crawcin();
  692.         Cconws("\r\033K");
  693.     }
  694.  
  695. #ifdef notdef
  696. /* if less than 1 megabyte free, turn off memory protection */
  697.     if (Mxalloc(-1L, 3) < ONE_MEG && !no_mem_prot) {
  698.         extern const char *insuff_mem_warning;
  699.         Cconws(insuff_mem_warning);
  700.         no_mem_prot = 1;
  701.     }
  702. #endif
  703.  
  704. /* look for ourselves as \AUTO\MINTNP.PRG; if so, we turn memory
  705.  * protection off
  706.  */
  707.     if (!no_mem_prot && Fsfirst("\\AUTO\\MINTNP.PRG",0) == 0)
  708.         no_mem_prot = 1;
  709.  
  710. /* check for GEM -- this must be done from user mode */
  711.     gem_active = check_for_gem();
  712.  
  713. /*
  714.  * get the current directory, so that we can switch back to it after
  715.  * the file systems are properly initialized
  716.  */
  717. /* set the current directory for the current process */
  718.     (void)Dgetpath(curpath, 0);
  719.     if (!*curpath) {
  720.         curpath[0] = '\\';
  721.         curpath[1] = 0;
  722.     }
  723.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  724.     if (!no_mem_prot)
  725.         save_mmu();        /* save current MMU setup */
  726.  
  727. /* get GEMDOS pointer to current basepage */
  728. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  729.    date, and (in newer versions of TOS) where the current basepage pointer
  730.    is kept; in older versions of TOS, it's at 0x602c
  731.  */
  732.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  733.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  734.  
  735.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  736.     if (tosvers == 0x100) {
  737.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  738.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  739.         else
  740.             tosbp = (BASEPAGE **) 0x602cL;
  741.         kbshft = (char *) 0x0e1bL;
  742.     } else {
  743.         tosbp = (BASEPAGE **) sysbase[10];
  744.         kbshft = (char *) sysbase[9];
  745.     }
  746.  
  747.     if (tosvers >= 0x0400 && tosvers <= 0x404) {
  748.         short *bconmap;
  749.         bconmap = (short *)Bconmap(-2);
  750.         if (bconmap[2] == 1) {    /* Falcon BIOS Bconmap is busted */
  751.             bconmap[2] = 3;
  752.         }
  753.         has_bconmap = 1;
  754.     } else {
  755. /* The TT TOS release notes are wrong... this is the real way to test
  756.  * for Bconmap ability
  757.  */
  758.         has_bconmap = (Bconmap(0) == 0);
  759.     }
  760.  
  761. /* initialize memory */
  762.     init_mem();
  763.  
  764. /* initialize the basic file systems */
  765.     init_filesys();
  766.  
  767. /* initialize processes */
  768.     init_proc();
  769.  
  770. /* initialize system calls */
  771.     init_dos();
  772.     init_bios();
  773.     init_xbios();
  774.  
  775. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  776.  * is called by init_intr; so make sure this is the last of the
  777.  * init_* things called!
  778.  */
  779.     init_intr();
  780.     enter_kernel(1);    /* we'll be making GEMDOS calls */
  781.  
  782. #if 0
  783.     if (!gem_active) {
  784. /* make MiNT invisible in the basepage chain, so that
  785.  * programs that rely on a certain basepage chain
  786.  * structure to determine whether or not they were run
  787.  * from the desktop will have a better chance of working.
  788.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  789.  * SOFTWARE: do *not* try counting basepages to figure
  790.  * out whether or not you were run from the desktop!!!
  791.  */
  792.         rootproc->base = _base->p_parent;
  793.     } else
  794. #endif
  795.         rootproc->base = _base;
  796.  
  797. /* set up standard file handles for the current process
  798.  * do this here, *after* init_intr has set the Rwabs vector,
  799.  * so that AHDI doesn't get upset by references to drive U:
  800.  */
  801.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  802.     if (!f) {
  803.         FATAL("unable to open CONSOLE device");
  804.     }
  805.     curproc->control = f;
  806.     curproc->handle[0] = f;
  807.     curproc->handle[1] = f;
  808.     f->links = 3;
  809.  
  810.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  811.     curproc->aux = f;
  812.     if (has_bconmap) {
  813.     /* If someone has already done a Bconmap call, then
  814.      * MODEM1 may no longer be the default
  815.      */
  816.         bconmap(curbconmap);
  817.         f = curproc->aux;    /* bconmap can change curproc->aux */
  818.     }
  819.     if (f) {
  820.         curproc->handle[2] = f;
  821.         f->links++;
  822.     }
  823.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  824.     if (f) {
  825.         curproc->handle[3] = curproc->prn = f;
  826.         f->links = 2;
  827.     }
  828.     if (f) {
  829.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  830.         curproc->midiin = curproc->midiout = f;
  831.         f->links = 2;
  832.     }
  833.  
  834. /* load external file systems */
  835. /* set path first to make sure that MiNT's directory matches
  836.  * GEMDOS's
  837.  */
  838.     (void)d_setpath(curpath);
  839.     
  840.     load_devdriver();
  841.  
  842. #ifndef PROFILING
  843. /* load_filesys causes media changes :-( */
  844.     load_filesys();
  845. #endif
  846.  
  847. /* note that load_filesys changed the
  848.  * directory on us!!
  849.  */
  850.     (void)d_setpath(curpath);
  851.     
  852. /* load the configuration file */
  853.     load_config();
  854.  
  855.     *((long *)0x4c2L) |= PSEUDODRVS;
  856.  
  857.     if (init_env == 0)
  858.         init_env = (char *)_base->p_env;
  859.  
  860. /* empty environment? Set the PATH variable to the root of the current drive */
  861.     if (init_env[0] == 0) {
  862.         static char path_env[] = "PATH=\0C:\0";
  863.         path_env[6] = curproc->curdrv + 'A';
  864.         init_env = path_env;
  865.     }
  866.  
  867. /* if we are MultiTOS, we're running in the AUTO folder, and our INIT is
  868.  * in fact GEM, take the exec_os() vector. (We know that INIT is GEM
  869.  * if the user told us so by using GEM= instead of INIT=.)
  870.  */
  871.     if (!gem_active && init_is_gem) {
  872.         xbra_install(&old_execos, EXEC_OS, (long ARGS_ON_STACK (*)())do_exec_os);
  873.     }
  874.  
  875. /* run any programs appearing after us in the AUTO folder */
  876.     run_auto_prgs();
  877.  
  878. /* run the initial program */
  879. /* if that program is in fact GEM, we start it via exec_os, otherwise
  880.  * we do it with Pexec.
  881.  * the logic is: if the user specified init_prg, and it is not
  882.  * GEM, then we try to execute it; if it *is* GEM (e.g. gem.sys),
  883.  * then we try to execute it if gem is already active, otherwise
  884.  * we jump through the exec_os vector (which we grabbed above) in
  885.  * order to start it. We *never* go through exec_os if we're not in
  886.  * the AUTO folder.
  887.  */
  888.     if (init_prg && (!init_is_gem || gem_active)) {
  889.         r = p_exec(0, (char *)init_prg, init_tail, init_env);
  890.     } else if (!gem_active) {   
  891.         BASEPAGE *bp; int pid;
  892.         bp = (BASEPAGE *)p_exec(7,
  893.           (char *)((long)F_FASTLOAD | F_ALTLOAD | F_ALTALLOC | F_PROT_S),
  894.           (char *)"\0", init_env);
  895.         bp->p_tbase = *((long *) EXEC_OS );
  896.         r = p_exec(106, (char *)"GEM", bp, 0L);
  897.         pid = (int)r;
  898.         if (pid > 0) {
  899.             do {
  900.                 r = p_wait3(0, (long *)0);
  901.             } while(pid != ((r & 0xffff0000L) >> 16));
  902.             r &= 0x0000ffff;
  903.         }
  904.     } else {
  905. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  906. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  907.             r = 0;
  908.     }
  909.  
  910.     if (r < 0 && init_prg) {
  911.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  912.         Cconws(buf);
  913.     }
  914.  
  915.     if (r) {
  916.         ksprintf(buf, "exit code: %ld\r\n", r);
  917.         Cconws(buf);
  918.     }
  919.  
  920.     rootproc->base = _base;
  921.  
  922. /* shut down all processes gracefully */
  923.     shutdown();
  924.  
  925. /* put everything back and exit */
  926.     if (!gem_active && init_is_gem) {
  927.     /* we stole exec_os above */
  928.         *((long *)EXEC_OS) = (long)old_execos.next;
  929.     }
  930.     restr_intr();
  931.     close_filesys();
  932.     if (!no_mem_prot)
  933.         restr_mmu();
  934.     restr_screen();
  935.  
  936.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  937.     Cconws("leaving MiNT\r\n");
  938.  
  939.     if (curs_off)
  940.         Cconws("\033f");    /* disable cursor */
  941.  
  942.     return 0;
  943. }
  944.  
  945.  
  946. /*
  947.  * cookie jar handling routines. The "cookie jar" is an area of memory
  948.  * reserved by TOS for TSR's and utility programs; the idea is that
  949.  * you put a cookie in the jar to notify people of available services.
  950.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  951.  * of TOS, the jar is always empty (unless someone added a cookie before
  952.  * us; POOLFIX does, for example).
  953.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  954.  * over) and frees it on exit. That's because TSR's run under MiNT
  955.  * will no longer be accessible after MiNT exits.
  956.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  957.  * and with the major version of MiNT in the high byte of the low word,
  958.  * and the minor version in the low byte.
  959.  */
  960.  
  961. void
  962. install_cookies()
  963. {
  964.     COOKIE *cookie;
  965.     int i, ncookies;
  966.     long ncsize;
  967.  
  968.     /* note that init_intr sets oldcookie to the old cookie jar */
  969.  
  970.     ncookies = 0;
  971.     cookie = oldcookie;
  972.     if (cookie) {
  973.         while (cookie->tag.aslong != 0) {
  974.         /* check for true FPU co-processor */
  975.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  976.                  (cookie->value >> 16) >= 2)
  977.                 fpu = 1;
  978.         /* check for _FLK cookie */
  979.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  980.                 flk = 1;
  981.             cookie++; ncookies++;
  982.         }
  983.     }
  984.  
  985.     /*
  986.      * We allocate the cookie jar in global memory so anybody can read
  987.      * it or write it. This code allocates at least 8 more cookies, and
  988.      * then rounds up to a QUANTUM boundary (that's what ROUND does). 
  989.      * Probably, nobody will have to allocate another cookie jar :-)
  990.      */
  991.  
  992.     /* NOTE: obviously, we can do this only if init_intr is called
  993.      * _after_ memory, processes, etc. have been initialized
  994.      */
  995.     ncsize = (ncookies+8)*sizeof(COOKIE);
  996.     ncsize = ROUND(ncsize);
  997.     newcookie = (COOKIE *)alloc_region(core, ncsize, PROT_G);
  998.  
  999. /* copy the old cookies to the new jar */
  1000.  
  1001.     for (i = 0; i < ncookies; i++) {
  1002.         newcookie[i] = oldcookie[i];
  1003.     }
  1004.  
  1005. /* install MiNT cookie */
  1006.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  1007.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  1008.     i++;
  1009.  
  1010. /* install _FLK cookie to indicate that file locking works */
  1011.     if (!flk) {
  1012.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  1013.         newcookie[i].value = 0;
  1014.         i++;
  1015.     }
  1016.  
  1017. /* jr: install PMMU cookie if memory protection is used */
  1018.     if (!no_mem_prot) {
  1019.         strncpy(newcookie[i].tag.aschar, "PMMU", 4);
  1020.         newcookie[i].value = 0;
  1021.         i++;
  1022.     }
  1023.  
  1024. /* the last cookie should have a 0 tag, and a value indicating the number
  1025.  * of slots, total
  1026.  */
  1027.  
  1028.     newcookie[i].tag.aslong = 0;
  1029.     newcookie[i].value = ncsize/sizeof(COOKIE);
  1030.  
  1031.     *CJAR = newcookie;
  1032.  
  1033. }
  1034.  
  1035. /*
  1036.  * Get the value of the _MCH cookie, if one exists; also set no_mem_prot if
  1037.  * there's a _CPU cookie and you're not on an '030, or if there is none.
  1038.  * This must be done in a separate routine because the machine type and CPU
  1039.  * type are needed when initializing the system, whereas install_cookies is
  1040.  * not called until everything is practically up.
  1041.  * In fact, getmch() should be called before *anything* else is
  1042.  * initialized, so that if we find a MiNT cookie already in the
  1043.  * jar we can bail out early and painlessly.
  1044.  */
  1045.  
  1046. static long
  1047. getmch()
  1048. {
  1049.     COOKIE *jar;
  1050.     int foundcpu = 0;
  1051.     int i;
  1052.     long *sysbase;
  1053.     extern int no_mem_prot;
  1054.  
  1055.     mcpu = 0;
  1056.     jar = *CJAR;    /* CJAR defined in cookie.h */
  1057.     if (jar) {
  1058.         while (jar->tag.aslong != 0) {
  1059.         /* check for machine type */
  1060.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  1061.                 mch = jar->value;
  1062.             } else if (!strncmp(jar->tag.aschar, "_CPU",4)) {
  1063.                     /* if not '030 then no memory protection */
  1064.                 mcpu = jar->value;
  1065.                     if (jar->value != 30) no_mem_prot = 1;
  1066.                     foundcpu = 1;
  1067.             } else if (!strncmp(jar->tag.aschar, "_VDO",4)) {
  1068.                 FalconVideo = (jar->value == 0x00030000L);
  1069.                 if (jar->value & 0xffff0000L)
  1070.                     screen_boundary = 15;
  1071.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  1072.                 Cconws("MiNT is already installed!!\r\n");
  1073.                 Pterm(2);
  1074.             } else if (!strncmp(jar->tag.aschar, "_AKP",4)) {
  1075.                 gl_lang = (int) ((jar->value >> 8) & 0x00ff);
  1076.             } else if (!strncmp(jar->tag.aschar, "PMMU",4)) {
  1077.                 /* jr: if PMMU cookie exists, someone else is
  1078.                    already using the PMMU */
  1079.                 Cconws ("MiNT: PMMU already in use, memory protection turned off.\r\n");
  1080.                 no_mem_prot = 1;
  1081.             }
  1082.             jar++;
  1083.         }
  1084.     }
  1085.     if (!foundcpu) no_mem_prot = 1;
  1086. /*
  1087.  * if no preference found, look at the country code to decide
  1088.  */
  1089.     if (gl_lang < 0) {
  1090.         sysbase = *((long **)(0x4f2L)); /* gets the RAM OS header */
  1091.         sysbase = (long *)sysbase[2];    /* gets the ROM one */
  1092.         i = (int) ((sysbase[7] & 0x7ffe0000L) >> 17L);
  1093.         switch(i) {
  1094.         case 1:        /* Germany */
  1095.         case 8:        /* Swiss German */
  1096.             gl_lang = 1;
  1097.             break;
  1098.         case 2:        /* France */
  1099.         case 7:        /* Swiss French */
  1100.             gl_lang = 2;
  1101.             break;
  1102.         case 4:        /* Spain */
  1103.             gl_lang = 4;
  1104.             break;
  1105.         case 5:        /* Italy */
  1106.             gl_lang = 5;
  1107.             break;
  1108.         default:
  1109.             gl_lang = 0;
  1110.             break;
  1111.         }
  1112.     }
  1113.     
  1114.  
  1115.     if (gl_lang >= MAXLANG || gl_lang < 0)
  1116.         gl_lang = 0;
  1117.     return 0L;
  1118. }
  1119.  
  1120. /*
  1121.  * routines for reading the configuration file
  1122.  * we allow the following commands in the file:
  1123.  * # anything        -- comment
  1124.  * INIT=file        -- specify boot program
  1125.  * CON=file        -- specify initial file/device for handles -1, 0, 1
  1126.  * PRN=file        -- specify initial file for handle 3
  1127.  * BIOSBUF=[yn]        -- if 'n' or 'N' then turn off BIOSBUF feature
  1128.  * DEBUG_LEVEL=n    -- set debug level to (decimal number) n
  1129.  * DEBUG_DEVNO=n    -- set debug device number to (decimal number) n
  1130.  * HARDSCROLL=n        -- set hard-scroll size to n, range 0-99.
  1131.  * SLICES=nnn        -- set multitasking granularity
  1132.  * echo message        -- print a message on the screen
  1133.  * alias drive path    -- make a fake drive pointing at a path
  1134.  * cd dir        -- change directory/drive
  1135.  * exec cmd args    -- execute a program
  1136.  * setenv name val    -- set up environment
  1137.  * sln file1 file2    -- create a symbolic link
  1138.  * ren file1 file2    -- rename a file
  1139.  *
  1140.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  1141.  * gets passed to children. This is rarely a problem if mint.prg is
  1142.  * in the auto folder.
  1143.  */
  1144.  
  1145. extern short bconbdev, bconbsiz;    /* from bios.c */
  1146.  
  1147. static void
  1148. doset(name, val)
  1149.     char *name, *val;
  1150. {
  1151.     char *t;
  1152.  
  1153.     if (!strcmp(name, "GEM")) {
  1154.         init_is_gem = 1;
  1155.         goto setup_init;
  1156.     } 
  1157.     if (!strcmp(name, "INIT")) {
  1158.         init_is_gem = 0;
  1159. setup_init:
  1160.         if (!*val) return;
  1161.         t = kmalloc(strlen(val)+1);
  1162.         if (!t) return;
  1163.         strcpy(t, val);
  1164.         init_prg = t;
  1165.         while (*t && !isspace(*t)) t++;
  1166. /* get the command tail, too */
  1167.         if (*t) {
  1168.             *t++ = 0;
  1169.             strncpy(init_tail+1, t, 125);
  1170.             init_tail[126] = 0;
  1171.             init_tail[0] = strlen(init_tail+1);
  1172.         }
  1173.         return;
  1174.     }
  1175.     if (!strcmp(name, "CON")) {
  1176.         FILEPTR *f;
  1177.         int i;
  1178.  
  1179.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  1180.         if (f) {
  1181.             for (i = -1; i < 2; i++) {
  1182.                 do_close(curproc->handle[i]);
  1183.                 curproc->handle[i] = f;
  1184.                 f->links++;
  1185.             }
  1186.             f->links--;    /* correct for overdoing it */
  1187.         }
  1188.         return;
  1189.     }
  1190.     if (!strcmp(name, "PRN")) {
  1191.         FILEPTR *f;
  1192.  
  1193.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  1194.         if (f) {
  1195.             do_close(curproc->handle[3]);
  1196.             do_close(curproc->prn);
  1197.             curproc->prn = curproc->handle[3] = f;
  1198.             f->links = 2;
  1199.         }
  1200.         return;
  1201.     }
  1202.     if (!strcmp(name, "BIOSBUF")) {
  1203.         if (*val == 'n' || *val == 'N') {
  1204.             if (bconbsiz) bflush();
  1205.             bconbdev = -1;
  1206.         }
  1207.         return;
  1208.     }
  1209.     if (!strcmp(name, "DEBUG_LEVEL")) {
  1210.         extern int debug_level;
  1211.         if (*val >= '0' && *val <= '9')
  1212.             debug_level = (int)atol(val);
  1213.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  1214.         return;
  1215.     }
  1216.     if (!strcmp(name, "DEBUG_DEVNO")) {
  1217.         extern int out_device;
  1218.         if (*val >= '0' && *val <= '9')
  1219.             out_device= (int)atol(val);
  1220.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  1221.         return;
  1222.     }
  1223.  
  1224. #ifdef FASTTEXT
  1225.     if (!strcmp(name, "HARDSCROLL")) {
  1226.         int i;
  1227.         extern int hardscroll;
  1228.  
  1229.         if (!strcmp(val, "AUTO")) {
  1230.             hardscroll = -1;
  1231.             return;
  1232.         }
  1233.         i = *val++;
  1234.         if (i < '0' || i > '9') return;
  1235.         hardscroll = i-'0';
  1236.         i = *val;
  1237.         if (i < '0' || i > '9') return;
  1238.         hardscroll = 10*hardscroll + i - '0';
  1239.         return;
  1240.     }
  1241. #endif
  1242.     if (!strcmp(name, "MAXMEM")) {
  1243.         long r;
  1244.  
  1245.         r = atol(val) * 1024L;
  1246.         if (r > 0)
  1247.             p_setlimit(2, r);
  1248.         return;
  1249.     }
  1250.     if (!strcmp(name, "SLICES")) {
  1251.         extern short time_slice;
  1252.  
  1253.         time_slice = atol(val);
  1254.         return;
  1255.     }
  1256.  
  1257.     if (!strcmp(name, "PSEUDODRIVES")) {
  1258.         FORCE("PSEUDODRIVES= no longer supported");
  1259.         return;
  1260.     }
  1261.     FORCE("Unknown variable `%s'", name);
  1262. }
  1263.  
  1264. /* Execute a line from the config file */
  1265. static void
  1266. do_line(line)
  1267.     char *line;
  1268. {
  1269.     char *cmd, *arg1, *arg2;
  1270.     char *newenv;
  1271.     char *t;
  1272.     int i;
  1273.     char delim;
  1274.  
  1275.     while (*line == ' ') line++;    /* skip whitespace at start of line */
  1276.     if (*line == '#') return;    /* ignore comments */
  1277.     if (!*line) return;        /* and also blank lines */
  1278.  
  1279.     cmd = line;
  1280. /* check for variable assignments (e.g. INIT=, etc.) */
  1281. /*
  1282.  * AGK: note we check for spaces whilst scanning so that an environment
  1283.  * variable may include an =, this has the unfortunate side effect that
  1284.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  1285.  */
  1286.     for (t = cmd; *t && *t != ' '; t++) {
  1287.         if (*t == '=') {
  1288.             *t++ = 0;
  1289.             doset(cmd, t);
  1290.             return;
  1291.         }
  1292.     }
  1293.  
  1294. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  1295.  
  1296.     while (*line && *line != ' ') line++;
  1297.     delim = ' ';
  1298.     if (*line) {
  1299.         *line++ = 0;
  1300.         while (*line == ' ') line++;
  1301.         if (*line == '"') {
  1302.             delim = '"';
  1303.             line++;
  1304.         }
  1305.     }
  1306.  
  1307.     if (!strcmp(cmd, "echo")) {
  1308.         c_conws(line); c_conws("\r\n");
  1309.         return;
  1310.     }
  1311.     arg1 = line;
  1312.     while (*line && *line != delim) line++;
  1313.     delim = ' ';
  1314.     if (*line) {
  1315.         *line++ = 0;
  1316.         while (*line == ' ') line++;
  1317.         if (*line == '"') {
  1318.             delim = '"';
  1319.             line++;
  1320.         }
  1321.     }
  1322.     if (!strcmp(cmd, "cd")) {
  1323.         int drv;
  1324.         (void)d_setpath(arg1);
  1325.         drv = toupper(*arg1) - 'A';
  1326.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1327.         return;
  1328.     }
  1329.     if (!strcmp(cmd, "exec")) {
  1330.         char cmdline[128];
  1331.         int i;
  1332.  
  1333.         i = strlen(line);
  1334.         if (i > 126) i = 126;
  1335.         cmdline[0] = i;
  1336.         strncpy(cmdline+1, line, i);
  1337.         cmdline[i+1] = 0;
  1338.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1339.         if (i == -33) {
  1340.             FORCE("%s: file not found", arg1);
  1341.         } else if (i < 0) {
  1342.             FORCE("%s: error while attempting to execute", arg1);
  1343.         }
  1344.         return;
  1345.     }
  1346.     if (!strcmp(cmd, "setenv")) {
  1347.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1348.                              env_len) {
  1349.             long j;
  1350.  
  1351.             env_len += 1024;
  1352.             newenv = (char *)m_xalloc(env_len, 0x13);
  1353.             if (init_env) {
  1354.                 t = init_env;
  1355.                 j = env_ptr - init_env;
  1356.                 env_ptr = newenv;
  1357.                 for (i = 0; i < j; i++)
  1358.                     *env_ptr++ = *t++;
  1359.                 if (init_env)
  1360.                     m_free((virtaddr)init_env);
  1361.             } else {
  1362.                 env_ptr = newenv;
  1363.             }
  1364.             init_env = newenv;
  1365.         }
  1366.         while (*arg1) {
  1367.             *env_ptr++ = *arg1++;
  1368.         }
  1369.         *env_ptr++ = '=';
  1370.         while (*line) {
  1371.             *env_ptr++ = *line++;
  1372.         }
  1373.         *env_ptr++ = 0;
  1374.         *env_ptr = 0;
  1375.         return;
  1376.     }
  1377.     if (!strcmp (cmd, "include")) {
  1378.         int fd = f_open (arg1, 0);
  1379.         if (fd < 0) {
  1380.         ALERT ("include: cannot open file %s", arg1);
  1381.         return;
  1382.         }
  1383.         do_file (fd);
  1384.         f_close (fd);
  1385.         return;
  1386.     }
  1387.     arg2 = line;
  1388.     while (*line && *line != delim) line++;
  1389.     if (*line) {
  1390.         *line = 0;
  1391.     }
  1392.     if (!strcmp(cmd, "alias")) {
  1393.         int drv;
  1394.         long r;
  1395.         fcookie root_dir;
  1396.         extern int aliasdrv[];
  1397.  
  1398.         drv = toupper(*arg1) - 'A';
  1399.         if (drv < 0 || drv >= NUM_DRIVES) {
  1400.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1401.             return;
  1402.         }
  1403.         r = path2cookie(arg2, NULL, &root_dir);
  1404.         if (r) {
  1405.             ALERT("alias: TOS error %ld while looking for %s",
  1406.                 r, arg2);
  1407.             return;
  1408.         }
  1409.         aliasdrv[drv] = root_dir.dev + 1;
  1410.         *((long *)0x4c2L) |= (1L << drv);
  1411.         release_cookie(&curproc->curdir[drv]);
  1412.         dup_cookie(&curproc->curdir[drv], &root_dir);
  1413.         release_cookie(&curproc->root[drv]);
  1414.         curproc->root[drv] = root_dir;
  1415.         return;
  1416.     }
  1417.     if (!strcmp(cmd, "sln")) {
  1418.         (void)f_symlink(arg1, arg2);
  1419.         return;
  1420.     }
  1421.     if (!strcmp(cmd, "ren")) {
  1422.         (void)f_rename(0, arg1, arg2);
  1423.         return;
  1424.     }
  1425.     FORCE("syntax error in mint.cnf near: %s", cmd);
  1426. }
  1427.  
  1428. #undef BUF
  1429. #undef LINE
  1430.  
  1431. #define BUF 512
  1432. #define LINE 256
  1433.  
  1434. static void
  1435. do_file(fd)
  1436.     int fd;
  1437. {
  1438.     long r;
  1439.     char buf[BUF+1], c;
  1440.     char line[LINE+1];
  1441.     char *from;
  1442.     int count = 0;
  1443.  
  1444.      buf[BUF] = 0;
  1445.     from = &buf[BUF];
  1446.     line[LINE] = 0;
  1447.  
  1448.     for(;;) {
  1449.         c = *from++;
  1450.         if (!c) {
  1451.             r = f_read(fd, (long)BUF, buf);
  1452.             if (r <= 0) break;
  1453.             buf[r] = 0;
  1454.             from = buf;
  1455.         } else if (c == '\r') {
  1456.             continue;
  1457.         } else if (c == '\n') {
  1458.             line[count] = 0;
  1459.             do_line(line);
  1460.             count = 0;
  1461.         } else {
  1462.             if (count < LINE) {
  1463.                 line[count++] = c;
  1464.             }
  1465.         }
  1466.     }
  1467.     if (count) {
  1468.         line[count] = 0;
  1469.         do_line(line);
  1470.     }
  1471.     f_close(fd);
  1472. }
  1473.  
  1474. void
  1475. load_config()
  1476. {
  1477.     int fd;
  1478.  
  1479.     fd = (int) f_open("mint.cnf", 0);
  1480.     if (fd < 0)
  1481.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1482.     if (fd < 0)
  1483.         fd = (int) f_open("\\multitos\\mint.cnf", 0);
  1484.     if (fd < 0) return;
  1485.     do_file(fd);
  1486.     f_close(fd);
  1487. }
  1488.  
  1489. /*
  1490.  * run programs in the AUTO folder that appear after MINT.PRG
  1491.  * some things to watch out for:
  1492.  * (1) make sure GEM isn't active
  1493.  * (2) make sure there really is a MINT.PRG in the auto folder
  1494.  */
  1495.  
  1496. /*
  1497.  * some global variables used to see if GEM is active
  1498.  */
  1499. static short aes_intout[64];
  1500. static short aes_dummy[64];
  1501. static short aes_globl[15];
  1502. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1503.  
  1504. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1505.              aes_dummy, aes_dummy };
  1506.  
  1507. /* check for whether GEM is active; remember, this *must* be done in
  1508.  * user mode
  1509.  */
  1510.  
  1511. static int
  1512. check_for_gem()
  1513. {
  1514.     call_aes(aes_pb);    /* does an appl_init */
  1515.     return aes_globl[0];
  1516. }
  1517.  
  1518. static void
  1519. run_auto_prgs()
  1520. {
  1521.     DTABUF *dta;
  1522.     long r;
  1523.     static char pathspec[32] = "\\AUTO\\";
  1524.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1525.  
  1526. /* if the AES is running, don't check AUTO */
  1527.  
  1528.     if (gem_active) {
  1529.         return;
  1530.     }
  1531.  
  1532. /* OK, now let's run through \\AUTO looking for
  1533.  * programs...
  1534.  */
  1535.     dta = (DTABUF *)f_getdta();
  1536.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1537.     while (r >= 0) {
  1538.         if (!strcmp(dta->dta_name, "MINT.PRG") ||
  1539.             !strcmp(dta->dta_name, "MINTNP.PRG"))
  1540.             runthem = 1;
  1541.         else if (runthem) {
  1542.             strcpy(pathspec+6, dta->dta_name);
  1543.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1544.         }
  1545.         r = f_snext();
  1546.     }
  1547. }
  1548.